package yzrilyzr.simplesynth.app.view;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.RectF;
import android.graphics.Region;
import android.util.AttributeSet;
import android.util.SparseArray;
import android.view.MotionEvent;
import android.view.View;

import yzrilyzr.util.Util;
import yzrilyzr.util.WidgetUtil;

public class PianoKeyboardView extends View{
	// 常量定义
	private static final int WHITE_KEY_COUNT=7; // 一个八度的白键数
	private static final int BLACK_KEY_COUNT=5; // 一个八度的黑键数
	// 颜色定义
	private static final int COLOR_WHITE_KEY=0xFFFFFFFF;
	private static final int COLOR_WHITE_KEY_PRESSED=0xFFAAAAAA;
	private static final int COLOR_BLACK_KEY=0xFF222222;
	private static final int COLOR_BLACK_KEY_PRESSED=0xFF666666;
	public void setKeyboardCallback(KeyboardCallback keyboardCallback){
		this.keyboardCallback=keyboardCallback;
	}
	private KeyboardCallback keyboardCallback=null;
	public int getBorderColor(){
		return borderColor;
	}
	public void setBorderColor(int borderColor){
		this.borderColor=borderColor;
	}
	private int borderColor=0xFF2196F3;
	private static final int COLOR_TEXT=0xFF000000;
	// 键盘状态
	private final SparseArray<Integer> pressedKeys=new SparseArray<>();
	private final SparseArray<Integer> activePointers=new SparseArray<>();
	// 键盘参数
	private int whiteKeyWidth;
	private int blackKeyWidth;
	private int keyHeight;
	private int whiteKeyCount=WHITE_KEY_COUNT*2; // 默认2个八度
	private int startKeyOffset=0; // 起始键偏移量（用于左右移动）
	// 绘画工具
	private final Paint paint=new Paint(Paint.ANTI_ALIAS_FLAG);
	private final Paint textPaint=new Paint(Paint.ANTI_ALIAS_FLAG);
	private final Paint borderPaint=new Paint(Paint.ANTI_ALIAS_FLAG);
	private final RectF keyRect=new RectF();
	private final Path blackKeyPath=new Path();
	// 添加成员变量保存键的区域
	private final SparseArray<RectF> whiteKeyRects=new SparseArray<>();
	private final SparseArray<Path> blackKeyPaths=new SparseArray<>();
	public PianoKeyboardView(Context context,AttributeSet attrs){
		super(context,attrs);
		init();
	}
	private void init(){
		textPaint.setColor(COLOR_TEXT);
		textPaint.setTextSize(WidgetUtil.px(12));
		textPaint.setTextAlign(Paint.Align.CENTER);
		borderPaint.setStyle(Paint.Style.STROKE);
		borderPaint.setStrokeWidth(WidgetUtil.px(1));
	}
	@Override
	protected void onSizeChanged(int w,int h,int oldw,int oldh){
		super.onSizeChanged(w,h,oldw,oldh);
		keyHeight=h;
		whiteKeyWidth=w/whiteKeyCount;
		blackKeyWidth=whiteKeyWidth*2/3;
	}
	private void drawWhiteKey(Canvas canvas,int position,int note,boolean pressed){
		keyRect.set(position*whiteKeyWidth,0,(position+1)*whiteKeyWidth,keyHeight);
		paint.setColor(pressed?COLOR_WHITE_KEY_PRESSED:COLOR_WHITE_KEY);
		canvas.drawRect(keyRect,paint);
		// 绘制边框
		borderPaint.setColor(borderColor);
		canvas.drawRect(keyRect,borderPaint);
		// 在C键上绘制音符标记
		if(note%12==0){
			String text="C"+(note/12-1);
			canvas.drawText(text,keyRect.centerX(),keyRect.top+keyHeight*0.85f,textPaint);
		}
	}
	private void drawBlackKey(Canvas canvas,int position,int note,boolean pressed){
		blackKeyPath.reset();
		float left=position*whiteKeyWidth+whiteKeyWidth-blackKeyWidth/2f;
		float right=left+blackKeyWidth;
		blackKeyPath.moveTo(left,0);
		blackKeyPath.lineTo(right,0);
		blackKeyPath.lineTo(right,keyHeight*2/3f);
		blackKeyPath.lineTo(left,keyHeight*2/3f);
		blackKeyPath.close();
		paint.setColor(pressed?COLOR_BLACK_KEY_PRESSED:COLOR_BLACK_KEY);
		canvas.drawPath(blackKeyPath,paint);
	}
	@Override
	public boolean onTouchEvent(MotionEvent event){
		int action=event.getActionMasked();
		int pointerIndex=event.getActionIndex();
		int pointerId=event.getPointerId(pointerIndex);
		float x=event.getX(pointerIndex);
		float y=event.getY(pointerIndex);
		switch(action){
			case MotionEvent.ACTION_DOWN:
			case MotionEvent.ACTION_POINTER_DOWN:
				handleKeyDown(x,y,pointerId);
				break;
			case MotionEvent.ACTION_MOVE:
				for(int i=0;i<event.getPointerCount();i++){
					pointerId=event.getPointerId(i);
					x=event.getX(i);
					y=event.getY(i);
					if(activePointers.get(pointerId,-1)!=-1){
						handleKeyMove(x,y,pointerId);
					}
				}
				break;
			case MotionEvent.ACTION_UP:
			case MotionEvent.ACTION_POINTER_UP:
			case MotionEvent.ACTION_CANCEL:
				if(activePointers.get(pointerId,-1)!=-1){
					handleKeyUp(pointerId);
				}
				break;
		}
		invalidate();
		return true;
	}
	@Override
	protected void onMeasure(int widthMeasureSpec,int heightMeasureSpec){
		super.onMeasure(widthMeasureSpec,heightMeasureSpec);
	}
	private void handleKeyDown(float x,float y,int pointerId){
		int note=getNoteAtPosition(x,y);
		if(note!=-1){
			float velocity=calculateVelocity(x,y,note);
			activePointers.put(pointerId,note);
			pressedKeys.put(note,pointerId);
			if(keyboardCallback!=null) keyboardCallback.noteOn(note,(int)(velocity*127));
		}
	}
	private void handleKeyMove(float x,float y,int pointerId){
		int oldNote=activePointers.get(pointerId,-1);
		if(oldNote==-1) return;
		int newNote=getNoteAtPosition(x,y);
		if(oldNote!=newNote){
			// 释放旧键
			pressedKeys.delete(oldNote);
			if(keyboardCallback!=null) keyboardCallback.noteOff(oldNote);
			// 按下新键
			if(newNote!=-1){
				float velocity=calculateVelocity(x,y,newNote);
				activePointers.put(pointerId,newNote);
				pressedKeys.put(newNote,pointerId);
				if(keyboardCallback!=null) keyboardCallback.noteOn(newNote,(int)(velocity*127));
			}
		}
		else{
			float velocity=calculateVelocity(x,y,newNote);
			if(keyboardCallback!=null) keyboardCallback.notePressure(newNote,(int)(velocity*127));
		}
	}
	private void handleKeyUp(int pointerId){
		int note=activePointers.get(pointerId,-1);
		if(note==-1) return;
		activePointers.remove(pointerId);
		pressedKeys.delete(note);
		if(keyboardCallback!=null) keyboardCallback.noteOff(note);
	}
	private int getWhiteKeyNote(int position){
		int[] whiteKeyNotes={0,2,4,5,7,9,11}; // C, D, E, F, G, A, B
		int octave=position/WHITE_KEY_COUNT;
		return 12*(octave+1)+whiteKeyNotes[position%WHITE_KEY_COUNT];
	}
	private boolean isBlackKey(int note){
		int[] blackKeyNotes={1,3,6,8,10}; // C#, D#, F#, G#, A#
		int semitone=note%12;
		for(int blackNote: blackKeyNotes){
			if(semitone==blackNote) return true;
		}
		return false;
	}
	private boolean hasBlackKeyBefore(int position){
		// 钢琴上黑键分布: C#(1), D#(1), F#(1), G#(1), A#(1)
		// 位置对应: 0(C),1(D),2(E),3(F),4(G),5(A),6(B)
		// 所以在E(2)和B(6)前没有黑键
		if(position==2||position==6) return false;
		// 其他位置检查是否有黑键
		int[] hasBlackKey={1,1,0,1,1,1,0}; // C#, D#, F#, G#, A#
		return hasBlackKey[position%hasBlackKey.length]==1;
	}
	@Override
	protected void onDraw(Canvas canvas){
		whiteKeyRects.clear();
		blackKeyPaths.clear();
		drawKeyboard(canvas);
	}
	private void drawKeyboard(Canvas canvas){
		// 绘制白键并保存区域
		for(int i=0;i<whiteKeyCount;i++){
			int note=getWhiteKeyNote(i+startKeyOffset);
			drawWhiteKey(canvas,i,note,pressedKeys.get(note,-1)!=-1);
			whiteKeyRects.put(note,new RectF(i*whiteKeyWidth,0,(i+1)*whiteKeyWidth,keyHeight));
		}
		// 绘制黑键并保存路径
		for(int i=0;i<whiteKeyCount;i++){
			int whiteKeyPosInOctave=(i+startKeyOffset)%WHITE_KEY_COUNT;
			if(hasBlackKeyBefore(whiteKeyPosInOctave)){
				// 完全重写黑键音符计算逻辑
				int octave=(i+startKeyOffset)/WHITE_KEY_COUNT;
				int blackKeyNote=getBlackKeyNoteForWhiteKeyPosition(whiteKeyPosInOctave,octave);
				if(blackKeyNote!=-1){
					drawBlackKey(canvas,i,blackKeyNote,pressedKeys.get(blackKeyNote,-1)!=-1);
					blackKeyPaths.put(blackKeyNote,new Path(blackKeyPath));
				}
			}
		}
	}
	// 新增方法：根据白键位置和八度计算对应的黑键音符
	private int getBlackKeyNoteForWhiteKeyPosition(int whiteKeyPosInOctave,int octave){
		// 钢琴键盘黑键布局（相对于白键位置）：
		// 位置0(C)右边是C#(1)
		// 位置1(D)右边是D#(3)
		// 位置3(F)右边是F#(6)
		// 位置4(G)右边是G#(8)
		// 位置5(A)右边是A#(10)
		// 基础音符（C4=60）
		int baseNote=12*(octave+1);
		switch(whiteKeyPosInOctave){
			case 0:
				return baseNote+1;   // C# (mi)
			case 1:
				return baseNote+3;   // D# (fa)
			case 3:
				return baseNote+6;   // F# (ti)
			case 4:
				return baseNote+8;   // G# (do)
			case 5:
				return baseNote+10;  // A# (re)
			default:
				return -1; // E和B没有右边的黑键
		}
	}
	private int getNoteAtPosition(float x,float y){
		// 先检查黑键（因为黑键在上层）
		for(int i=0;i<blackKeyPaths.size();i++){
			int note=blackKeyPaths.keyAt(i);
			Path path=blackKeyPaths.valueAt(i);
			if(path!=null){
				Region region=new Region();
				region.setPath(path,new Region(0,0,getWidth(),(int)(keyHeight*2/3f)));
				if(region.contains((int)x,(int)y)){
					return note;
				}
			}
		}
		// 再检查白键
		for(int i=0;i<whiteKeyRects.size();i++){
			int note=whiteKeyRects.keyAt(i);
			RectF rect=whiteKeyRects.valueAt(i);
			if(rect!=null&&rect.contains(x,y)){
				return note;
			}
		}
		return -1;
	}
	private float calculateVelocity(float x,float y,int note){
		boolean isBlackKey=isBlackKey(note);
		float relativeY=y/(isBlackKey?keyHeight*2/3f:keyHeight);
		return Util.clamp01(relativeY);
	}
	// 公共方法 - 用于外部控制
	public void increaseKeys(){
		if(whiteKeyCount<52){ // 钢琴标准88键中有52个白键
			whiteKeyCount++;
			whiteKeyWidth=getWidth()/whiteKeyCount;
			blackKeyWidth=whiteKeyWidth*2/3;
			requestLayout();
			invalidate();
		}
	}
	public int getWhiteKeyCount(){
		return whiteKeyCount;
	}
	public void setWhiteKeyCount(int whiteKeyCount){
		this.whiteKeyCount=whiteKeyCount;
	}
	public void decreaseKeys(){
		if(whiteKeyCount>WHITE_KEY_COUNT){ // 最少1个八度(7个白键)
			whiteKeyCount--;
			whiteKeyWidth=getWidth()/whiteKeyCount;
			blackKeyWidth=whiteKeyWidth*2/3;
			// 确保偏移量不会超出范围
			if(startKeyOffset>whiteKeyCount-WHITE_KEY_COUNT){
				startKeyOffset=whiteKeyCount-WHITE_KEY_COUNT;
			}
			requestLayout();
			invalidate();
		}
	}
	public void moveLeft(){
		if(startKeyOffset>0){
			startKeyOffset--;
			invalidate();
		}
	}
	public int getStartKeyOffset(){
		return startKeyOffset;
	}
	public void setStartKeyOffset(int startKeyOffset){
		this.startKeyOffset=startKeyOffset;
	}
	public void moveRight(){
		// 确保不会移动到超出总键数范围
		if(startKeyOffset<getMaxKeyOffset()){
			startKeyOffset++;
			invalidate();
		}
	}
	private int getMaxKeyOffset(){
		// 最大偏移量是总键数减去可视键数
		return Math.max(0,52-whiteKeyCount);
	}
}